﻿#include "MirrorPass.h"

#include "../../../Common/Singleton.h"
#include "../ResourceManager/Dx2GeometryManager.h"
#include "../ResourceManager/Dx2MaterialManager.h"
#include "../ResourceManager/Dx2ShaderAndLayoutManager.h"
#include "../ResourceManager/Dx2RootSignatureManager.h"

void MirrorPass::BuildRenderItems(std::vector<std::unique_ptr<RenderItem>>& allRitems,UINT& lastObjIndex)
{
    auto mirrorRitem = std::make_unique<RenderItem>();
    mirrorRitem->World = MathHelper::Identity4x4();
    mirrorRitem->TexTransform = MathHelper::Identity4x4();
    mirrorRitem->ObjCBIndex = lastObjIndex;
    lastObjIndex++;
    
    mirrorRitem->Mat = Singleton<Dx2MaterialManager>::Instance()->GetMaterial("icemirror").get();
    mirrorRitem->Geo = Singleton<Dx2GeometryManager>::Instance()->GetGeometry("roomGeo").get();
    mirrorRitem->IndexCount = mirrorRitem->Geo->DrawArgs["mirror"].IndexCount;
    mirrorRitem->StartIndexLocation = mirrorRitem->Geo->DrawArgs["mirror"].StartIndexLocation;
    mirrorRitem->BaseVertexLocation = mirrorRitem->Geo->DrawArgs["mirror"].BaseVertexLocation;

    mRenderItems.push_back(mirrorRitem.get());
    allRitems.push_back(move(mirrorRitem)); //mirror 只是渲染到模板缓存
}

void MirrorPass::BuildPSOs(ID3D12Device* device, DXGI_FORMAT BackBufferFormat, DXGI_FORMAT DepthStencilFormat,
    bool _4xMsaaState, UINT _4xMsaaQuality)
{
    D3D12_GRAPHICS_PIPELINE_STATE_DESC markMirrorsPsoDesc;
    ZeroMemory(&markMirrorsPsoDesc,sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
	
    markMirrorsPsoDesc.InputLayout = {Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetInputLayout().data(),(UINT)Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetInputLayout().size()};
    markMirrorsPsoDesc.pRootSignature = Singleton<Dx2RootSignatureManager>::Instance()->GetRootSignature(RootSignatureType::Default).Get();
	
    markMirrorsPsoDesc.VS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("standardVS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("standardVS")->GetBufferSize()
    };
	
    markMirrorsPsoDesc.PS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("opaquePS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("opaquePS")->GetBufferSize()
    };
	
    markMirrorsPsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
    markMirrorsPsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
    markMirrorsPsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
    markMirrorsPsoDesc.SampleMask = UINT_MAX;
    markMirrorsPsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
    markMirrorsPsoDesc.NumRenderTargets = 1;
    markMirrorsPsoDesc.RTVFormats[0] = BackBufferFormat;
    markMirrorsPsoDesc.SampleDesc.Count = _4xMsaaState? 4:1;
    markMirrorsPsoDesc.SampleDesc.Quality = _4xMsaaState? (_4xMsaaQuality - 1):0;
    markMirrorsPsoDesc.DSVFormat = DepthStencilFormat;

    CD3DX12_BLEND_DESC mirrorBlendState(D3D12_DEFAULT);
    mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0;

    D3D12_DEPTH_STENCIL_DESC mirrorDSS;
    mirrorDSS.DepthEnable = true;
    mirrorDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
    mirrorDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
    mirrorDSS.StencilEnable = true;
    mirrorDSS.StencilReadMask = 0xff;
    mirrorDSS.StencilWriteMask = 0xff;

    mirrorDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    mirrorDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    mirrorDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
    mirrorDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;

    mirrorDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    mirrorDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    mirrorDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
    mirrorDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;

    markMirrorsPsoDesc.BlendState = mirrorBlendState;
    markMirrorsPsoDesc.DepthStencilState = mirrorDSS;

    ThrowIfFailed(device->CreateGraphicsPipelineState(&markMirrorsPsoDesc,IID_PPV_ARGS(&mPso)));
}

void MirrorPass::Draw(ID3D12GraphicsCommandList* cmdList, CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuHandler, UINT srvHeapSize,
    UINT objCBByteSize, UINT matCBByteSize, UINT passCBByteSize, 
    ID3D12Resource* objectCB, ID3D12Resource* matCB,ID3D12Resource* passCB,
    const PassConstants& passValue,
    ID3D12Resource* OutColorRenderTarget,D3D12_CPU_DESCRIPTOR_HANDLE OutColorRenderTargetView,D3D12_CPU_DESCRIPTOR_HANDLE OutDepthStentilView
 
    )
{
    cmdList->OMSetStencilRef(1);
    cmdList->SetPipelineState(mPso.Get());
    DrawRenderItem(cmdList,hGpuHandler,srvHeapSize,objCBByteSize,matCBByteSize,objectCB,matCB,mRenderItems);
}
